//
//  _SW__Slider_LoopPlugIn.m
//  [SW] Slider Loop
//
//  Created by David Langford on 13/01/10.
//  Copyright (c) 2010 Sentient Worlds. All rights reserved.
//

/* It's highly recommended to use CGL macros instead of changing the current context for plug-ins that perform OpenGL rendering */
#import <OpenGL/CGLMacro.h>

#import "_SW__Slider_LoopPlugIn.h"

#define	kQCPlugIn_Name				@"[SW] Slider Loop"
#define	kQCPlugIn_Description		@"By connecting the outputs to a Replicate In Space patch you can create an infinite loop of objects. Any questions please email me at langford.d@gmail.com\n\nThe entire replication is called 'Slider', The instance being replicated is referred to as 'Item'.\n\nUse 'Slide' to slide the items across."

@implementation _SW__Slider_LoopPlugIn

/*
Here you need to declare the input / output properties as dynamic as Quartz Composer will handle their implementation
@dynamic inputFoo, outputBar;
*/

@dynamic	inputSliderX;
@dynamic	inputItemWidth;
@dynamic	inputGroupOffset;
@dynamic	inputCopies;

@dynamic	outputLeftBoundry;
@dynamic	outputRightBoundry;
@dynamic	outputSliderCenterForInsideGroup;

@dynamic	outputFinalTranslationX;
@dynamic	outputOriginX;
@dynamic	outputCopies;

+ (NSDictionary*) attributes
{
	/*
	Return a dictionary of attributes describing the plug-in (QCPlugInAttributeNameKey, QCPlugInAttributeDescriptionKey...).
	*/
	
	return [NSDictionary dictionaryWithObjectsAndKeys:kQCPlugIn_Name, QCPlugInAttributeNameKey, kQCPlugIn_Description, QCPlugInAttributeDescriptionKey, nil];
}

+ (NSDictionary*) attributesForPropertyPortWithKey:(NSString*)key
{
	/*
	Specify the optional attributes for property based ports (QCPortAttributeNameKey, QCPortAttributeDefaultValueKey...).
	*/
	if([key isEqualToString:@"inputCopies"])
		return [NSDictionary dictionaryWithObjectsAndKeys:@"Number of Copies", QCPortAttributeNameKey
				, [NSNumber numberWithFloat: 1.0], QCPortAttributeMinimumValueKey
				, [NSNumber numberWithFloat: 1.0], QCPortAttributeDefaultValueKey
				, nil];
	if([key isEqualToString:@"inputSliderX"])
		return [NSDictionary dictionaryWithObjectsAndKeys:@"Slider X", QCPortAttributeNameKey
				, [NSNumber numberWithFloat: 0.0], QCPortAttributeDefaultValueKey
				, nil];
	if([key isEqualToString:@"inputGroupOffset"])
		return [NSDictionary dictionaryWithObjectsAndKeys:@"Slide", QCPortAttributeNameKey
				, [NSNumber numberWithFloat: 0.0], QCPortAttributeDefaultValueKey
				, nil];
	if([key isEqualToString:@"inputItemWidth"])
		return [NSDictionary dictionaryWithObjectsAndKeys:@"Item Width", QCPortAttributeNameKey
				, [NSNumber numberWithFloat: 0.0], QCPortAttributeDefaultValueKey
				, nil];
	
	
	if([key isEqualToString:@"outputCopies"])
		return [NSDictionary dictionaryWithObjectsAndKeys:@"Copies", QCPortAttributeNameKey
				, nil];
	if([key isEqualToString:@"outputOriginX"])
		return [NSDictionary dictionaryWithObjectsAndKeys:@"Origin X", QCPortAttributeNameKey
				, nil];
	if([key isEqualToString:@"outputFinalTranslationX"])
		return [NSDictionary dictionaryWithObjectsAndKeys:@"Final Translation X", QCPortAttributeNameKey
				, nil];

	
	
	if([key isEqualToString:@"outputLeftBoundry"])
		return [NSDictionary dictionaryWithObjectsAndKeys:@"Left Boundry", QCPortAttributeNameKey
				, nil];
	if([key isEqualToString:@"outputRightBoundry"])
		return [NSDictionary dictionaryWithObjectsAndKeys:@"Right Boundry", QCPortAttributeNameKey
				, nil];
	if([key isEqualToString:@"outputSliderCenterForInsideGroup"])
		return [NSDictionary dictionaryWithObjectsAndKeys:@"Group Focus X", QCPortAttributeNameKey
				, nil];
	
	return nil;
}

+ (QCPlugInExecutionMode) executionMode
{
	/*
	Return the execution mode of the plug-in: kQCPlugInExecutionModeProvider, kQCPlugInExecutionModeProcessor, or kQCPlugInExecutionModeConsumer.
	*/
	
	return kQCPlugInExecutionModeProcessor;
}

+ (QCPlugInTimeMode) timeMode
{
	/*
	Return the time dependency mode of the plug-in: kQCPlugInTimeModeNone, kQCPlugInTimeModeIdle or kQCPlugInTimeModeTimeBase.
	*/
	
	return kQCPlugInTimeModeNone;
}

- (id) init
{
	if(self = [super init]) {
		/*
		Allocate any permanent resource required by the plug-in.
		*/
	}
	
	return self;
}

- (void) finalize
{
	/*
	Release any non garbage collected resources created in -init.
	*/
	
	[super finalize];
}

- (void) dealloc
{
	/*
	Release any resources created in -init.
	*/
	
	[super dealloc];
}

@end

@implementation _SW__Slider_LoopPlugIn (Execution)

- (BOOL) startExecution:(id<QCPlugInContext>)context
{
	/*
	Called by Quartz Composer when rendering of the composition starts: perform any required setup for the plug-in.
	Return NO in case of fatal failure (this will prevent rendering of the composition to start).
	*/
	
	return YES;
}

- (void) enableExecution:(id<QCPlugInContext>)context
{
	/*
	Called by Quartz Composer when the plug-in instance starts being used by Quartz Composer.
	*/
}

- (BOOL) execute:(id<QCPlugInContext>)context atTime:(NSTimeInterval)time withArguments:(NSDictionary*)arguments
{
	/*
	Called by Quartz Composer whenever the plug-in instance needs to execute.
	Only read from the plug-in inputs and produce a result (by writing to the plug-in outputs or rendering to the destination OpenGL context) within that method and nowhere else.
	Return NO in case of failure during the execution (this will prevent rendering of the current frame to complete).
	
	The OpenGL context for rendering can be accessed and defined for CGL macros using:
	CGLContextObj cgl_ctx = [context CGLContextObj];
	*/
	
	// Set the inputs to variables so we can debug easier
	double itemWidth = self.inputItemWidth;
	double sliderX = self.inputSliderX;
	double copies = self.inputCopies;
	double wantedGroupOffset = self.inputGroupOffset;
	
	// Check the parameters are valid
	if (itemWidth == 0)
		return YES;
	
	// Find information about the item with regard to the slider boundry
	double halfItemWidth = itemWidth/2;
	double sliderBoundryLeft = halfItemWidth*-1;
	double sliderBoundryRight = halfItemWidth;
	
	// Keep the relative centre of the panorama always between the boundries
	double actualGroupOffset = wantedGroupOffset;
	while (actualGroupOffset > sliderBoundryRight)
	{
		actualGroupOffset -= itemWidth;
	}
	while (actualGroupOffset < sliderBoundryLeft)
	{
		actualGroupOffset += itemWidth;
	}
	
	// Find the output values, use variables for debugging
	double originX = (actualGroupOffset + sliderX)-(itemWidth*(copies-1)/2);
	double finalTranslationX = itemWidth*(copies-1); // this one is relative to origin
	self.outputOriginX = originX;
	self.outputFinalTranslationX = finalTranslationX;
	self.outputCopies = copies;
	
	// Set these values, which can be used for debug
	self.outputLeftBoundry = sliderBoundryLeft + sliderX;
	self.outputRightBoundry = sliderBoundryRight + sliderX;
	self.outputSliderCenterForInsideGroup = -1*actualGroupOffset + sliderX;
	
	return YES;
}

- (void) disableExecution:(id<QCPlugInContext>)context
{
	/*
	Called by Quartz Composer when the plug-in instance stops being used by Quartz Composer.
	*/
}

- (void) stopExecution:(id<QCPlugInContext>)context
{
	/*
	Called by Quartz Composer when rendering of the composition stops: perform any required cleanup for the plug-in.
	*/
}

@end
